#pragma once

class IRenderer;
extern IRenderer* g_Renderer;

class IRendererEvent;
class IRequest;
class ITypeRenderer;
class RBlendState;
class RRasterizerState;
class RDepthstencilState;
class RSamplerState;
class RMaterial;
class RShader;
class RConst;
class RTexture;
class RFramebuffer;
class RBuffer;
class RVertexArray;
class RFont;
class SemanticInfo;
class DynGeometryMgr;
class RendererStorageMgr;
class TextMgr;
class PostprocessMgr;
class MaterialMgr;
class QueueMgr;

namespace ESemantic
{
	enum Type
	{
		iPosition0,
		iPosition1,
		iNormal0,
		iNormal1,
		iTexcoord0,
		iTexcoord1,
		iColor0,
		iColor1,
		iInstancing,
		iIndices,
		oColor0,
		oColor1,
		oColor2,
		oColor3
	};
};

namespace EShader
{
	enum Type
	{
		VertexShader,
		GeometryShader,
		FragmentShader,

		Unknown
	};
};

namespace EConst
{
	enum Type
	{
		Float1,
		Float4,
		Int4,
		Mat4
	};
};

namespace ETopology
{
	enum Type
	{
		Triangles,
		TriangleStrip,
		Points,
		Lines
	};
};

namespace EOpenGLConstant
{
	enum Type
	{
		max_uniform_buffer_bindings,
		uniform_buffer_offset_alignment,
		Count
	};
}

namespace EEngineUniform
{
	enum Type
	{
		Bumpmapping_TextureMultiplier_1f,
		Bumpmapping_Strength_1f,
		
		ConstantColor_4f
	};
}

struct RStats
{
	int DrawArrays;
	int DrawElements;
	int DrawArraysInstanced;
	int DrawElementsInstanced;

	void Reset()
	{
		DrawArrays = 0;
		DrawElements = 0;
		DrawArraysInstanced = 0;
		DrawElementsInstanced = 0;
	}
};

class IRenderer
{
public:
	IRenderer();
	virtual ~IRenderer();

	virtual void		InitializeOpenGL(int res_x, int res_y) = 0;
	virtual int			GetOpenGLConstant(EOpenGLConstant::Type type) = 0;

	virtual void		GetTypeRenderer(const std::string& name, uint& arg, ITypeRenderer** type) = 0;
	virtual void		AddTypeRenderer(ITypeRenderer* typerenderer, const std::string& name, uint arg) = 0;
	virtual void		AddRendererEvent(IRendererEvent* event) = 0;
	virtual void		AddRequest(void** ret, IRequest* request) = 0;

	virtual const SemanticInfo*	GetSemanticInfo(const std::string& name) = 0;
	virtual const SemanticInfo*	GetSemanticInfo(ESemantic::Type type) = 0;

	virtual void				RenderFrame() = 0;

	virtual int					GetResX() = 0;
	virtual int					GetResY() = 0;

	virtual void				ResetMatrices() = 0;

	virtual float*				GetModelMatrix() = 0;
	virtual void				SetModelMatrix(const GLM_MAT4x4& matrix) = 0;

	virtual float*				GetViewMatrix() = 0;
	virtual float*				GetProjectionMatrix() = 0;
	virtual void				SetCamera(const GLM_MAT4x4& view, const GLM_MAT4x4& proj, float near, float far, const glm::vec3& position) = 0;

	virtual void				SetEngineUniform(EEngineUniform::Type type, void* ptn) = 0;
	virtual uint				GetEngineUniformSize(EEngineUniform::Type type) = 0;

	virtual void				BindMaterial(const RMaterial* material) = 0;

	virtual DynGeometryMgr*		GetDynGeometryMgr() = 0;
	virtual RendererStorageMgr* GetRendererStorageMgr() = 0;
	virtual TextMgr*			GetTextMgr() = 0;
	virtual MaterialMgr*		GetMaterialMgr() = 0;
	virtual PostprocessMgr*		GetPostprocessMgr() = 0;
	virtual QueueMgr*			GetQueueMgr() = 0;

	virtual void				Draw(const RVertexArray* vao, ETopology::Type type, uint vertices, uint instances, const RVertexArray* instvao) = 0;
	virtual void				DrawOrigin(float length) = 0;

	virtual void				ResetRenderStats() = 0;
	virtual const RStats&		GetRenderStats() = 0;

	static void			CreateInstance();
	static void			DestroyInstance();
};

